﻿using System.ComponentModel.Composition;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using IssueVision.EntityModel;
using IssueVision.Common;
using SL.IdentityModel.Services;

namespace IssueVision.ViewModel
{
    [Export(ViewModelTypes.LoginFormViewModel, typeof(ViewModelBase))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class LoginFormViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IAuthenticationModel _authenticationModel;
        private IPasswordResetModel _passwordResetModel;
        #endregion "Private Data Members"

        #region "Constructor"
        [ImportingConstructor]
        public LoginFormViewModel(IAuthenticationModel authModel, IPasswordResetModel passModel)
        {
            _authenticationModel = authModel;
            _passwordResetModel = passModel;

            // Set up event handling
            _authenticationModel.SignInCompleted += _authenticationModel_SignInCompleted;
            _passwordResetModel.GetPasswordQuestionCompleted += _passwordResetModel_GetPasswordQuestionCompleted;
            _passwordResetModel.ResetPasswordCompleted += _passwordResetModel_ResetPasswordCompleted;

            // Show user login screen first
            IsFlipped = false;

            // Clear any previous error message
            LoginScreenErrorMessage = null;
            ResetPasswordScreenErrorMessage = null;

            // Clear the user name and password
            CurrentUser = new User();
        }
        #endregion "Constructor"

        #region "Public Properties"

        private bool _isFlipped;

        public bool IsFlipped
        {
            get { return _isFlipped; }
            private set
            {
                if (value != _isFlipped)
                {
                    _isFlipped = value;
                    RaisePropertyChanged("IsFlipped");
                }
            }
        }

        private User _currentUser;

        public User CurrentUser
        {
            get { return _currentUser; }
            private set
            {
                if (!ReferenceEquals(_currentUser, value))
                {
                    _currentUser = value;
                    RaisePropertyChanged("CurrentUser");
                }
            }
        }

        private PasswordResetUser _currentPasswordResetUser;

        public PasswordResetUser CurrentPasswordResetUser
        {
            get { return _currentPasswordResetUser; }
            private set
            {
                if (!ReferenceEquals(_currentPasswordResetUser, value))
                {
                    _currentPasswordResetUser = value;
                    RaisePropertyChanged("CurrentPasswordResetUser");
                }
            }
        }

        private string _loginScreenErrorMessage;

        public string LoginScreenErrorMessage
        {
            get { return _loginScreenErrorMessage; }
            private set
            {
                if (value != _loginScreenErrorMessage)
                {
                    _loginScreenErrorMessage = value;
                    RaisePropertyChanged("LoginScreenErrorMessage");
                }
            }
        }

        private string _resetPasswordScreenErrorMessage;

        public string ResetPasswordScreenErrorMessage
        {
            get { return _resetPasswordScreenErrorMessage; }
            private set
            {
                if (value != _resetPasswordScreenErrorMessage)
                {
                    _resetPasswordScreenErrorMessage = value;
                    RaisePropertyChanged("ResetPasswordScreenErrorMessage");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand<User> _loginCommand;

        public RelayCommand<User> LoginCommand
        {
            get
            {
                if (_loginCommand == null)
                {
                    _loginCommand = new RelayCommand<User>(
                        g => OnLoginCommand(g),
                        g => g != null);
                }
                return _loginCommand;
            }
        }

        private void OnLoginCommand(User g)
        {
            if (!_authenticationModel.IsBusy)
            {
                // clear any previous error message
                LoginScreenErrorMessage = null;
                // only call SignInAsync when all input are validated
                if (g.TryValidate("Name") && g.TryValidate("Password"))
                    _authenticationModel.SignInAsync(g.Name, g.Password);
            }
        }

        private RelayCommand<User> _resetNowCommand;

        public RelayCommand<User> ResetNowCommand
        {
            get
            {
                if (_resetNowCommand == null)
                {
                    _resetNowCommand = new RelayCommand<User>(
                        g => OnResetNowCommand(g),
                        g => g != null);     
                }
                return _resetNowCommand;
            }
        }

        private void OnResetNowCommand(User g)
        {
            if (!_passwordResetModel.IsBusy)
            {
                // clear any previous error message
                LoginScreenErrorMessage = null;
                // only call GetPasswordQuestionByUserNameAsync when user name is valid
                if (g.TryValidate("Name"))
                {
                    _passwordResetModel.GetPasswordQuestionByUserNameAsync(g.Name);
                }
            }
        }

        private RelayCommand _backToLoginCommand;

        public RelayCommand BackToLoginCommand
        {
            get
            {
                if (_backToLoginCommand == null)
                {
                    _backToLoginCommand = new RelayCommand(
                        () => OnBackToLoginCommand());
                }
                return _backToLoginCommand;
            }
        }

        private void OnBackToLoginCommand()
        {
            // clear any previous error message
            ResetPasswordScreenErrorMessage = null;
            // clear the password reset screen
            CurrentPasswordResetUser = new PasswordResetUser();
            // and flip the screen.
            IsFlipped = false;
        }

        private RelayCommand<PasswordResetUser> _resetPasswordCommand;

        public RelayCommand<PasswordResetUser> ResetPasswordCommand
        {
            get
            {
                if (_resetPasswordCommand == null)
                {
                    _resetPasswordCommand = new RelayCommand<PasswordResetUser>(
                        g => OnResetPasswordCommand(g),
                        g => g != null);
                }
                return _resetPasswordCommand;
            }
        }

        private void OnResetPasswordCommand(PasswordResetUser g)
        {
            if (!_passwordResetModel.IsBusy)
            {
                // clear any previous error message
                ResetPasswordScreenErrorMessage = null;
                // only call ResetPasswordAsync when all input are validated
                if (g.TryValidate())
                    _passwordResetModel.ResetPasswordAsync(g);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        /// <summary>
        /// Event handler for SignInCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _authenticationModel_SignInCompleted(object sender, SignInEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.User != null)
                {
                    if (e.User.ClaimsIdentity.IsAuthenticated)
                    {
                        // login successful, clear the login screen
                        CurrentUser = new User();
                    }
                }
            }
            else
            {
                LoginScreenErrorMessage = e.Error.Message;
            }
        }

        /// <summary>
        /// Event handler for GetPasswordQuestionCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _passwordResetModel_GetPasswordQuestionCompleted(object sender, ResultArgs<string> e)
        {
            if (!e.HasError)
            {
                if (!(string.IsNullOrWhiteSpace(e.Results)))
                {
                    // populate the password reset screen
                    CurrentPasswordResetUser = new PasswordResetUser
                                                   {
                                                       Name = CurrentUser.Name,
                                                       PasswordQuestion = e.Results
                                                   };
                    // found the user, clear the login screen before leaving
                    CurrentUser = new User();

                    // and flip the screen.
                    IsFlipped = true;
                }
            }
            else
            {
                LoginScreenErrorMessage = e.Error.Message;
            }
        }

        /// <summary>
        /// Event handler for ResetPasswordCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _passwordResetModel_ResetPasswordCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                // populate the user name of the login screen
                CurrentUser = new User {Name = CurrentPasswordResetUser.Name};
                // reset password successful, clear the reset password screen before leaving
                CurrentPasswordResetUser = new PasswordResetUser();

                // and flip the screen.
                IsFlipped = false;
            }
            else
            {
                ResetPasswordScreenErrorMessage = e.Error.Message;
            }
        }

        #endregion "Private Methods"
    }
}
